#ifndef __M_DB_H__
#define __M_DB_H__

#include"util.hpp"
#include <mutex>          // std::mutex
#include <cassert>

class user_table
{
    private:
        MYSQL *_mysql;//数据库连接
        std::mutex _mutex;//互斥锁
    public:
        user_table(const std::string &host,
        const std:: string &username,
        const std:: string &password,
        const std:: string &dbname,
        uint16_t port=3306)
        {
            _mysql=mysql_util::mysql_create(host,username,password,dbname,port);
            assert(_mysql!=NULL);
        }

        ~user_table()
        {
            mysql_util::mysql_destroy(_mysql);  
            _mysql=NULL;
        }

        bool insert(Json::Value &user)//注册用户信息
        {
            #define INSERT_USER "insert user values(null, '%s', '%s', 1000, 0, 0);"
            if (user["password"].isNull() || user["username"].isNull()) 
            {
                    DLOG("INPUT PASSWORD OR USERNAME");
                    return false;
            }
            char sql[4096]={0};
            sprintf(sql,INSERT_USER,user["username"].asString().c_str(),user["password"].asString().c_str());
            bool ret=mysql_util::mysql_exec(_mysql,sql);
            if(ret==false)
            {
                DLOG("insert user failed!\n");
                return false;
            }
            return true;
        }

        bool login(Json::Value &user) 
        {
            if (user["password"].isNull() || user["username"].isNull()) {
                DLOG("INPUT PASSWORD OR USERNAME");
                return false;
            }
            //以用户名和密码共同作为查询过滤条件，查询到数据则表示用户名密码一致，没有信息则用户名密码错误
            #define LOGIN_USER "select id, score, total_count, win_count from user where username='%s' and password='%s';"
            char sql[4096] = {0};
            sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());
            MYSQL_RES *res = NULL;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                bool ret = mysql_util::mysql_exec(_mysql, sql);
                if (ret == false) {
                        DLOG("user login failed!!\n");
                        return false;
                }
                //按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
                res = mysql_store_result(_mysql);
                if (res == NULL) 
                {
                        DLOG("have no login user info!!");
                        return false;
                }
            }
            int row_num = mysql_num_rows(res);
            if (row_num != 1) 
            {
                DLOG("the user information queried is not unique!!");
                return false;
            }
            MYSQL_ROW row = mysql_fetch_row(res);
            user["id"] = (Json::UInt64)std::stol(row[0]);
            user["score"] = (Json::UInt64)std::stol(row[1]);
            user["total_count"] = std::stoi(row[2]);
            user["win_count"] = std::stoi(row[3]);
            mysql_free_result(res);
            return true;
        }

        
        bool select_by_name(const std::string &name,Json::Value &user)//根据用户名查询用户
        {
            #define SELECT_USER "select id, score, total_count, win_count from user where username='%s';"
            char sql[4096]={0};
            sprintf(sql,SELECT_USER,name.c_str());
            MYSQL_RES *res = NULL;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                bool ret = mysql_util::mysql_exec(_mysql, sql);
                if (ret == false) {
                        DLOG("get user by name failed!!\n");
                        return false;
                }
                //按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
                res = mysql_store_result(_mysql);
                if (res == NULL) {
                        DLOG("have no user info!!");
                        return false;
                }
            }
            int row_num=mysql_num_rows(res);
            if(row_num!=1)
            {
                DLOG("the user information is not unique!\n");
                return false;
            }
            MYSQL_ROW row = mysql_fetch_row(res);
            user["id"] = (Json::UInt64)std::stol(row[0]);
            user["username"] = name;               
            user["score"] = (Json::UInt64)std::stol(row[1]);
            user["total_count"] = std::stoi(row[2]);
            user["win_count"] = std::stoi(row[3]);
            mysql_free_result(res);
            return true;
        }
        // 通过用户名获取用户信息
          bool select_by_id(uint64_t id, Json::Value &user) {
                #define USER_BY_ID "select username, score, total_count, win_count from user where id=%ld;"
               char sql[4096] = {0};
               sprintf(sql, USER_BY_ID, id);
               MYSQL_RES *res = NULL;
               {
                    std::unique_lock<std::mutex> lock(_mutex);
                    bool ret = mysql_util::mysql_exec(_mysql, sql);
                    if (ret == false) {
                         DLOG("get user by id failed!!\n");
                         return false;
                    }
                    //按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
                    res = mysql_store_result(_mysql);
                    if (res == NULL) {
                         DLOG("have no user info!!");
                         return false;
                    }
               }
               int row_num = mysql_num_rows(res);
               if (row_num != 1) {
                    DLOG("the user information queried is not unique!!");
                    return false;
               }
               MYSQL_ROW row = mysql_fetch_row(res);
               user["id"] = (Json::UInt64)id;
               user["username"] = row[0];
               user["score"] = (Json::UInt64)std::stol(row[1]);
               user["total_count"] = std::stoi(row[2]);
               user["win_count"] = std::stoi(row[3]);
               mysql_free_result(res);
               return true;
          }
        //用户win
        bool win(uint64_t id)//用户win
        {
            #define WIN_USER "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%ld;"
            char sql[4096]={0};
            sprintf(sql,WIN_USER,id);
            bool ret=mysql_util::mysql_exec(_mysql,sql);
            if(ret==false)
            {
                DLOG("update win user info failed!!\n");
                return false;
            }
            return true;
        }
        //用户lose
        bool lose(uint64_t id)//用户lose
        {
            #define LOSE_USER "update user set score=score-30,total_count=total_count+1 where id=%ld;"
            char sql[4096]={0};
            sprintf(sql,LOSE_USER,id);
            bool ret=mysql_util::mysql_exec(_mysql,sql);
            if(ret==false)
            {
                DLOG("update lose user info failed!!\n");
                return false;
            }
            return true;
        }
};

#endif
